namespace PickGold.Charting
{
	using System;
	using System.Drawing;
	using System.Drawing.Drawing2D;
	using System.Runtime.InteropServices;

	internal class Matrix3D
	{
		private float _angleX;
		private float _angleY;
		private LightStyle _lightStyle;
		private Point3D[] _lightVectors = new Point3D[7];
		private float[][] _mainMatrix;
		internal float _perspective;
		private float _perspectiveFactor = float.NaN;
		private float _perspectiveZ;
		private bool _rightAngleAxis;
		private float _scale;
		private float _shiftX;
		private float _shiftY;
		private float _translateX;
		private float _translateY;
		private float _translateZ;

		private void ApplyPerspective(Point3D[] points)
		{
			foreach (Point3D pointd in points)
			{
				pointd.X = this._translateX + ((pointd.X - this._translateX) / (1f + ((this._perspectiveZ - pointd.Z) * this._perspectiveFactor)));
				pointd.Y = this._translateY + ((pointd.Y - this._translateY) / (1f + ((this._perspectiveZ - pointd.Z) * this._perspectiveFactor)));
			}
		}

		private float GetAngle(Point3D a, Point3D b)
		{
			return (float)Math.Acos(((double)(((a.X * b.X) + (a.Y * b.Y)) + (a.Z * b.Z))) / (Math.Sqrt((double)(((a.X * a.X) + (a.Y * a.Y)) + (a.Z * a.Z))) * Math.Sqrt((double)(((b.X * b.X) + (b.Y * b.Y)) + (b.Z * b.Z)))));
		}

		private Color GetBrightGradientColor(Color beginColor, double position)
		{
			position *= 2.0;
			double num = 0.5;
			if (position < num)
			{
				return ChartGraphics.GetGradientColor(Color.FromArgb(beginColor.A, 0xff, 0xff, 0xff), beginColor, (1.0 - num) + position);
			}
			if ((-num + position) < 1.0)
			{
				return ChartGraphics.GetGradientColor(beginColor, Color.Black, -num + position);
			}
			return Color.FromArgb(beginColor.A, 0, 0, 0);
		}

		internal void GetLight(Color surfaceColor, out Color front, out Color back, out Color left, out Color right, out Color top, out Color bottom)
		{
			switch (this._lightStyle)
			{
				case LightStyle.None:
					front = surfaceColor;
					left = surfaceColor;
					top = surfaceColor;
					back = surfaceColor;
					right = surfaceColor;
					bottom = surfaceColor;
					return;

				case LightStyle.Simplistic:
					front = surfaceColor;
					left = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25);
					top = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15);
					back = surfaceColor;
					right = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25);
					bottom = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15);
					return;
			}
			if (this._rightAngleAxis)
			{
				Point3D a = new Point3D(0f, 0f, -1f);
				Point3D[] points = new Point3D[] { a };
				this.RightAngleProjection(points);
				if ((this._angleY >= 45f) || (this._angleY <= -45f))
				{
					front = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, ((double)this.GetAngle(a, this._lightVectors[1])) / 3.1415926535897931);
					back = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, ((double)this.GetAngle(a, this._lightVectors[2])) / 3.1415926535897931);
					left = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.0);
					right = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.0);
				}
				else
				{
					front = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.0);
					back = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 1.0);
					left = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, ((double)this.GetAngle(a, this._lightVectors[3])) / 3.1415926535897931);
					right = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, ((double)this.GetAngle(a, this._lightVectors[4])) / 3.1415926535897931);
				}
				top = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, ((double)this.GetAngle(a, this._lightVectors[5])) / 3.1415926535897931);
				bottom = ChartGraphics.GetGradientColor(surfaceColor, Color.Black, ((double)this.GetAngle(a, this._lightVectors[6])) / 3.1415926535897931);
			}
			else
			{
				Point3D pointd2 = new Point3D(0f, 0f, 1f);
				front = this.GetBrightGradientColor(surfaceColor, ((double)this.GetAngle(pointd2, this._lightVectors[1])) / 3.1415926535897931);
				back = this.GetBrightGradientColor(surfaceColor, ((double)this.GetAngle(pointd2, this._lightVectors[2])) / 3.1415926535897931);
				left = this.GetBrightGradientColor(surfaceColor, ((double)this.GetAngle(pointd2, this._lightVectors[3])) / 3.1415926535897931);
				right = this.GetBrightGradientColor(surfaceColor, ((double)this.GetAngle(pointd2, this._lightVectors[4])) / 3.1415926535897931);
				top = this.GetBrightGradientColor(surfaceColor, ((double)this.GetAngle(pointd2, this._lightVectors[5])) / 3.1415926535897931);
				bottom = this.GetBrightGradientColor(surfaceColor, ((double)this.GetAngle(pointd2, this._lightVectors[6])) / 3.1415926535897931);
			}
		}

		internal Color GetPolygonLight(Point3D[] points, Color surfaceColor, bool visiblePolygon, float rotation, SurfaceNames surfaceName, bool switchSeriesOrder)
		{
			Color color = surfaceColor;
			Point3D a = new Point3D(0f, 0f, 1f);
			switch (this._lightStyle)
			{
				case LightStyle.None:
					return color;

				case LightStyle.Simplistic:
					{
						Point3D pointd2 = new Point3D();
						pointd2.X = points[0].X - points[1].X;
						pointd2.Y = points[0].Y - points[1].Y;
						pointd2.Z = points[0].Z - points[1].Z;
						Point3D pointd3 = new Point3D();
						pointd3.X = points[2].X - points[1].X;
						pointd3.Y = points[2].Y - points[1].Y;
						pointd3.Z = points[2].Z - points[1].Z;
						Point3D pointd4 = new Point3D();
						pointd4.X = (pointd2.Y * pointd3.Z) - (pointd2.Z * pointd3.Y);
						pointd4.Y = (pointd2.Z * pointd3.X) - (pointd2.X * pointd3.Z);
						pointd4.Z = (pointd2.X * pointd3.Y) - (pointd2.Y * pointd3.X);
						if (surfaceName != SurfaceNames.Left)
						{
							if (surfaceName != SurfaceNames.Right)
							{
								float angle;
								float num2;
								if (surfaceName == SurfaceNames.Front)
								{
									return surfaceColor;
								}
								if (surfaceName == SurfaceNames.Back)
								{
									return surfaceColor;
								}
								if (switchSeriesOrder)
								{
									if ((rotation > 0f) && (rotation <= 90f))
									{
										angle = this.GetAngle(pointd4, this._lightVectors[3]);
										num2 = this.GetAngle(pointd4, this._lightVectors[4]);
									}
									else
									{
										angle = this.GetAngle(pointd4, this._lightVectors[4]);
										num2 = this.GetAngle(pointd4, this._lightVectors[3]);
									}
								}
								else if ((rotation > 0f) && (rotation <= 90f))
								{
									angle = this.GetAngle(pointd4, this._lightVectors[4]);
									num2 = this.GetAngle(pointd4, this._lightVectors[3]);
								}
								else
								{
									angle = this.GetAngle(pointd4, this._lightVectors[3]);
									num2 = this.GetAngle(pointd4, this._lightVectors[4]);
								}
								if (Math.Abs((float)(angle - num2)) < 0.01)
								{
									return ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25);
								}
								if (angle < num2)
								{
									return ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.25);
								}
							}
							return ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15);
						}
						return ChartGraphics.GetGradientColor(surfaceColor, Color.Black, 0.15);
					}
			}
			Point3D pointd5 = new Point3D();
			pointd5.X = points[0].X - points[1].X;
			pointd5.Y = points[0].Y - points[1].Y;
			pointd5.Z = points[0].Z - points[1].Z;
			Point3D pointd6 = new Point3D();
			pointd6.X = points[2].X - points[1].X;
			pointd6.Y = points[2].Y - points[1].Y;
			pointd6.Z = points[2].Z - points[1].Z;
			Point3D b = new Point3D();
			b.X = (pointd5.Y * pointd6.Z) - (pointd5.Z * pointd6.Y);
			b.Y = (pointd5.Z * pointd6.X) - (pointd5.X * pointd6.Z);
			b.Z = (pointd5.X * pointd6.Y) - (pointd5.Y * pointd6.X);
			if (surfaceName == SurfaceNames.Front)
			{
				a.Z *= -1f;
				return this.GetBrightGradientColor(surfaceColor, ((double)this.GetAngle(a, this._lightVectors[2])) / 3.1415926535897931);
			}
			if (surfaceName == SurfaceNames.Back)
			{
				a.Z *= -1f;
				return this.GetBrightGradientColor(surfaceColor, ((double)this.GetAngle(a, this._lightVectors[1])) / 3.1415926535897931);
			}
			if (visiblePolygon)
			{
				a.Z *= -1f;
			}
			return this.GetBrightGradientColor(surfaceColor, ((double)this.GetAngle(a, b)) / 3.1415926535897931);
		}

		private void GetValues(Point3D[] points)
		{
			float[] mulVector = new float[4];
			float[] resultVector = new float[4];
			foreach (Point3D pointd in points)
			{
				mulVector[0] = pointd.X;
				mulVector[1] = pointd.Y;
				mulVector[2] = pointd.Z;
				mulVector[3] = 1f;
				this.MultiplyVector(mulVector, ref resultVector);
				pointd.X = resultVector[0];
				pointd.Y = resultVector[1];
				pointd.Z = resultVector[2];
			}
		}

		internal void Initialize(RectangleF innerPlotRectangle, float depth, float angleX, float angleY, float perspective, bool rightAngleAxis)
		{
			this.Reset();
			this._translateX = innerPlotRectangle.X + (innerPlotRectangle.Width / 2f);
			this._translateY = innerPlotRectangle.Y + (innerPlotRectangle.Height / 2f);
			this._translateZ = depth / 2f;
			float width = innerPlotRectangle.Width;
			float height = innerPlotRectangle.Height;
			this._perspective = perspective;
			this._rightAngleAxis = rightAngleAxis;
			this._angleX = angleX;
			this._angleY = angleY;
			angleX = (angleX / 180f) * 3.141593f;
			angleY = (angleY / 180f) * 3.141593f;
			Point3D[] points = this.Set3DBarPoints(width, height, depth);
			this.Translate(this._translateX, this._translateY, 0f);
			if (!rightAngleAxis)
			{
				this.Rotate((double)angleX, RotationAxis.X);
				this.Rotate((double)angleY, RotationAxis.Y);
			}
			else if (this._angleY >= 45f)
			{
				this.Rotate(1.5707963267948966, RotationAxis.Y);
			}
			else if (this._angleY <= -45f)
			{
				this.Rotate(-1.5707963267948966, RotationAxis.Y);
			}
			this.GetValues(points);
			float minValue = float.MinValue;
			if ((perspective != 0f) || rightAngleAxis)
			{
				foreach (Point3D pointd in points)
				{
					if (pointd.Z > minValue)
					{
						minValue = pointd.Z;
					}
				}
				this._perspectiveZ = minValue;
			}
			if (perspective != 0f)
			{
				this._perspectiveFactor = perspective / 2000f;
				this.ApplyPerspective(points);
			}
			if (rightAngleAxis)
			{
				this.RightAngleProjection(points);
				float num4 = 0f;
				float num5 = 0f;
				float num6 = 0f;
				float num7 = 0f;
				foreach (Point3D pointd2 in points)
				{
					if (((pointd2.X - this._translateX) < 0f) && (Math.Abs((float)(pointd2.X - this._translateX)) > num4))
					{
						num4 = Math.Abs((float)(pointd2.X - this._translateX));
					}
					if (((pointd2.X - this._translateX) >= 0f) && (Math.Abs((float)(pointd2.X - this._translateX)) > num6))
					{
						num6 = Math.Abs((float)(pointd2.X - this._translateX));
					}
					if (((pointd2.Y - this._translateY) < 0f) && (Math.Abs((float)(pointd2.Y - this._translateY)) > num5))
					{
						num5 = Math.Abs((float)(pointd2.Y - this._translateY));
					}
					if (((pointd2.Y - this._translateY) >= 0f) && (Math.Abs((float)(pointd2.Y - this._translateY)) > num7))
					{
						num7 = Math.Abs((float)(pointd2.Y - this._translateY));
					}
				}
				this._shiftX = (num6 - num4) / 2f;
				this._shiftY = (num7 - num5) / 2f;
				this.RightAngleShift(points);
			}
			float num8 = float.MinValue;
			float num9 = float.MinValue;
			foreach (Point3D pointd3 in points)
			{
				if (num8 < ((Math.Abs((float)(pointd3.X - this._translateX)) / width) * 2f))
				{
					num8 = (Math.Abs((float)(pointd3.X - this._translateX)) / width) * 2f;
				}
				if (num9 < ((Math.Abs((float)(pointd3.Y - this._translateY)) / height) * 2f))
				{
					num9 = (Math.Abs((float)(pointd3.Y - this._translateY)) / height) * 2f;
				}
			}
			this._scale = (num9 > num8) ? num9 : num8;
			this.Scale(points);
		}

		internal void InitLight(LightStyle lightStyle)
		{
			this._lightStyle = lightStyle;
			this._lightVectors[0] = new Point3D(0f, 0f, 0f);
			this._lightVectors[1] = new Point3D(0f, 0f, 1f);
			this._lightVectors[2] = new Point3D(0f, 0f, -1f);
			this._lightVectors[3] = new Point3D(-1f, 0f, 0f);
			this._lightVectors[4] = new Point3D(1f, 0f, 0f);
			this._lightVectors[5] = new Point3D(0f, -1f, 0f);
			this._lightVectors[6] = new Point3D(0f, 1f, 0f);
			this.TransformPoints(this._lightVectors, false);
			Point3D pointd1 = this._lightVectors[1];
			pointd1.X -= this._lightVectors[0].X;
			Point3D pointd2 = this._lightVectors[1];
			pointd2.Y -= this._lightVectors[0].Y;
			Point3D pointd3 = this._lightVectors[1];
			pointd3.Z -= this._lightVectors[0].Z;
			Point3D pointd4 = this._lightVectors[2];
			pointd4.X -= this._lightVectors[0].X;
			Point3D pointd5 = this._lightVectors[2];
			pointd5.Y -= this._lightVectors[0].Y;
			Point3D pointd6 = this._lightVectors[2];
			pointd6.Z -= this._lightVectors[0].Z;
			Point3D pointd7 = this._lightVectors[3];
			pointd7.X -= this._lightVectors[0].X;
			Point3D pointd8 = this._lightVectors[3];
			pointd8.Y -= this._lightVectors[0].Y;
			Point3D pointd9 = this._lightVectors[3];
			pointd9.Z -= this._lightVectors[0].Z;
			Point3D pointd10 = this._lightVectors[4];
			pointd10.X -= this._lightVectors[0].X;
			Point3D pointd11 = this._lightVectors[4];
			pointd11.Y -= this._lightVectors[0].Y;
			Point3D pointd12 = this._lightVectors[4];
			pointd12.Z -= this._lightVectors[0].Z;
			Point3D pointd13 = this._lightVectors[5];
			pointd13.X -= this._lightVectors[0].X;
			Point3D pointd14 = this._lightVectors[5];
			pointd14.Y -= this._lightVectors[0].Y;
			Point3D pointd15 = this._lightVectors[5];
			pointd15.Z -= this._lightVectors[0].Z;
			Point3D pointd16 = this._lightVectors[6];
			pointd16.X -= this._lightVectors[0].X;
			Point3D pointd17 = this._lightVectors[6];
			pointd17.Y -= this._lightVectors[0].Y;
			Point3D pointd18 = this._lightVectors[6];
			pointd18.Z -= this._lightVectors[0].Z;
		}

		public bool IsInitialized()
		{
			return (this._mainMatrix != null);
		}

		private float[][] Multiply(float[][] mulMatrix, MatrixOrder order, bool setMainMatrix)
		{
			float[][] numArray = new float[][] { new float[4], new float[4], new float[4], new float[4] };
			for (int i = 0; i < 4; i++)
			{
				for (int j = 0; j < 4; j++)
				{
					numArray[i][j] = 0f;
					for (int k = 0; k < 4; k++)
					{
						if (order == MatrixOrder.Prepend)
						{
							numArray[i][j] += this._mainMatrix[i][k] * mulMatrix[k][j];
						}
						else
						{
							numArray[i][j] += mulMatrix[i][k] * this._mainMatrix[k][j];
						}
					}
				}
			}
			if (setMainMatrix)
			{
				this._mainMatrix = numArray;
			}
			return numArray;
		}

		private void MultiplyVector(float[] mulVector, ref float[] resultVector)
		{
			for (int i = 0; i < 3; i++)
			{
				resultVector[i] = 0f;
				for (int j = 0; j < 4; j++)
				{
					resultVector[i] += this._mainMatrix[i][j] * mulVector[j];
				}
			}
		}

		private void Reset()
		{
			this._mainMatrix = new float[][] { new float[4], new float[4], new float[4], new float[4] };
			for (int i = 0; i < 4; i++)
			{
				for (int j = 0; j < 4; j++)
				{
					if (i == j)
					{
						this._mainMatrix[i][j] = 1f;
					}
					else
					{
						this._mainMatrix[i][j] = 0f;
					}
				}
			}
		}

		private void RightAngleProjection(Point3D[] points)
		{
			float num3;
			float num = 45f;
			float num2 = this._angleX / 45f;
			if (this._angleY >= 45f)
			{
				num3 = (this._angleY - 90f) / num;
			}
			else if (this._angleY <= -45f)
			{
				num3 = (this._angleY + 90f) / num;
			}
			else
			{
				num3 = this._angleY / num;
			}
			foreach (Point3D pointd in points)
			{
				pointd.X += (this._perspectiveZ - pointd.Z) * num3;
				pointd.Y -= (this._perspectiveZ - pointd.Z) * num2;
			}
		}

		private void RightAngleShift(Point3D[] points)
		{
			foreach (Point3D pointd in points)
			{
				pointd.X -= this._shiftX;
				pointd.Y -= this._shiftY;
			}
		}

		private void Rotate(double angle, RotationAxis axis)
		{
			float[][] mulMatrix = new float[][] { new float[4], new float[4], new float[4], new float[4] };
			angle = -1.0 * angle;
			for (int i = 0; i < 4; i++)
			{
				for (int j = 0; j < 4; j++)
				{
					if (i == j)
					{
						mulMatrix[i][j] = 1f;
					}
					else
					{
						mulMatrix[i][j] = 0f;
					}
				}
			}
			switch (axis)
			{
				case RotationAxis.X:
					mulMatrix[1][1] = (float)Math.Cos(angle);
					mulMatrix[1][2] = (float)-Math.Sin(angle);
					mulMatrix[2][1] = (float)Math.Sin(angle);
					mulMatrix[2][2] = (float)Math.Cos(angle);
					break;

				case RotationAxis.Y:
					mulMatrix[0][0] = (float)Math.Cos(angle);
					mulMatrix[0][2] = (float)Math.Sin(angle);
					mulMatrix[2][0] = (float)-Math.Sin(angle);
					mulMatrix[2][2] = (float)Math.Cos(angle);
					break;

				case RotationAxis.Z:
					mulMatrix[0][0] = (float)Math.Cos(angle);
					mulMatrix[0][1] = (float)-Math.Sin(angle);
					mulMatrix[1][0] = (float)Math.Sin(angle);
					mulMatrix[1][1] = (float)Math.Cos(angle);
					break;
			}
			this.Multiply(mulMatrix, MatrixOrder.Prepend, true);
		}

		private void Scale(Point3D[] points)
		{
			foreach (Point3D pointd in points)
			{
				pointd.X = this._translateX + ((pointd.X - this._translateX) / this._scale);
				pointd.Y = this._translateY + ((pointd.Y - this._translateY) / this._scale);
			}
		}

		private Point3D[] Set3DBarPoints(float dx, float dy, float dz)
		{
			return new Point3D[] { new Point3D(-dx / 2f, -dy / 2f, dz / 2f), new Point3D(dx / 2f, -dy / 2f, dz / 2f), new Point3D(dx / 2f, dy / 2f, dz / 2f), new Point3D(-dx / 2f, dy / 2f, dz / 2f), new Point3D(-dx / 2f, -dy / 2f, -dz / 2f), new Point3D(dx / 2f, -dy / 2f, -dz / 2f), new Point3D(dx / 2f, dy / 2f, -dz / 2f), new Point3D(-dx / 2f, dy / 2f, -dz / 2f) };
		}

		public void TransformPoints(Point3D[] points)
		{
			this.TransformPoints(points, true);
		}

		private void TransformPoints(Point3D[] points, bool withPerspective)
		{
			if (this._mainMatrix == null)
			{
				throw new InvalidOperationException(SR.ExceptionMatrix3DNotinitialized);
			}
			foreach (Point3D pointd in points)
			{
				pointd.X -= this._translateX;
				pointd.Y -= this._translateY;
				pointd.Z -= this._translateZ;
			}
			this.GetValues(points);
			if ((this._perspective != 0f) && withPerspective)
			{
				this.ApplyPerspective(points);
			}
			if (this._rightAngleAxis)
			{
				this.RightAngleProjection(points);
				this.RightAngleShift(points);
			}
			this.Scale(points);
		}

		private void Translate(float dx, float dy, float dz)
		{
			float[][] mulMatrix = new float[][] { new float[4], new float[4], new float[4], new float[4] };
			for (int i = 0; i < 4; i++)
			{
				for (int j = 0; j < 4; j++)
				{
					if (i == j)
					{
						mulMatrix[i][j] = 1f;
					}
					else
					{
						mulMatrix[i][j] = 0f;
					}
				}
			}
			mulMatrix[0][3] = dx;
			mulMatrix[1][3] = dy;
			mulMatrix[2][3] = dz;
			this.Multiply(mulMatrix, MatrixOrder.Prepend, true);
		}

		internal float AngleX
		{
			get
			{
				return this._angleX;
			}
		}

		internal float AngleY
		{
			get
			{
				return this._angleY;
			}
		}

		internal float Perspective
		{
			get
			{
				return this._perspective;
			}
		}

		private enum RotationAxis
		{
			X,
			Y,
			Z
		}
	}
}

